/**
 * Created by clw on 2018/11/28.
 */

/* 树形图谱函数，
 使用前需引入
 base-tools.js
 d3.js(V3版本)
 */
var d3 = require('d3')

/**
 * Created by clw on 2018/11/16.
 */

/**
 * 为SVGElement增加getTransformToElement, 因为新版chrome(dev 48.0)移除了getTransformToElement
 */
function add_getTransformToElement() {
    // 获取当前element向elem转化的转化矩阵, 如{a: 1, b: 0, c: 0, d: 1, e: 0, f: 0}
    SVGElement.prototype.getTransformToElement = SVGElement.prototype.getTransformToElement || function(elem) {
        return elem.getScreenCTM().inverse().multiply(this.getScreenCTM())
    }
}

add_getTransformToElement()


/** 获取滚轮事件名字
 * 现代浏览器事件: wheel
 * ie事件: mousewheel
 * 老版本firefox: MozMousePixelScroll
 * ie11可同时触发 wheel和mousewheel
 *   当触发wheel时没有wheelDelta值; 触发mousewheel时有wheelDelta值
 * MDN链接: https://developer.mozilla.org/en-US/docs/Web/Events/wheel
 *
 * firefox 向下为 正数， 其余浏览器 向下为负数
 *
 * @return {*} String 事件名字
 */
function getWheelEventName() {
    var support
    support = 'onwheel' in document.createElement('div') ? 'wheel' : // Modern browsers support "wheel"
        document.onmousewheel !== undefined ? 'mousewheel' : // Webkit and IE support at least "mousewheel"
        'DOMMouseScroll' // let's assume that remaining browsers are older Firefox
    support = support === 'DOMMouseScroll' ? 'MozMousePixelScroll' : support
    return support
}


// 获取字符串长度，汉字算2个字符
function getByteLen(val) {
    var len = 0
    for (var i = 0; i < val.length; i++) {
        var a = val.charAt(i)
        var reg = /[^\x00-\xff]/ig
        if (a.match(reg) !== null) {
            len += 2
        } else {
            len += 1
        }
    }
    return len
}


// 把svgELeFrom中的点的坐标转化为svgEleTo里面的坐标
function getMatrixPoint(point, svgEleFrom, svgEleTo, matrix) {
    if (!matrix) {
        matrix = svgEleFrom.getTransformToElement(svgEleTo)
    }
    // 获取点击点在svg_mini的g的坐标系中的位置
    return point.matrixTransform(matrix)
}

/** 元素排序
 * a - b > 0 从小到大
 * a - b < 0 从大到小
 * @param a
 * @param b
 * @return {number}
 */
function sortNode(a, b) {
    var a_z_index = a.sort || 0
    var b_z_index = b.sort || 0
    if (a_z_index > b_z_index) {
        return 1
    } else if (a_z_index < b_z_index) {
        return -1
    } else {
        return 0
    }
}


// 获取节点实际显示宽和高
function getBoundaryBox(node) {
    var box
    try {
        box = node.getBBox()
    } catch (e) {
        box = {
            x: node.clientLeft,
            y: node.clientTop,
            width: node.clientWidth,
            height: node.clientHeight
        }
    }
    return box
}

/** 获取g在屏幕中显示区域的大小, 即为box和another相交的部分
 * @param box
 * @param another
 * @return {*}
 */
function intersect(box, another) {
    // if (!another instanceof Box) {
    //     another = new Box(another);
    // }
    var left = Math.max(box.left, another.left),
        right = Math.min(box.right, another.right),
        top = Math.max(box.top, another.top),
        bottom = Math.min(box.bottom, another.bottom)
    if (left > right || top > bottom) return defaultRectBox()
    return getBox(left, top, right - left, bottom - top)
}

// 得到一个矩形区域的宽高信息
function getBox(x, y, width, height) {
    var box = arguments[0]
    var rect = {}
    if (box && typeof box === 'object') {
        x = box.x
        y = box.y
        width = box.width
        height = box.height
    }
    if (width < 0) {
        x -= width = -width
    }
    if (height < 0) {
        y -= height = -height
    }
    // 矩形区域的 x 坐标
    rect.x = x || 0
        // 矩形区域的 y 坐标
    rect.y = y || 0

    // 矩形区域的宽度
    rect.width = width || 0

    // 矩形区域的高度
    rect.height = height || 0

    // 矩形区域的最左侧坐标，等价于 x 的值
    rect.left = rect.x

    // 矩形区域的最右侧坐标，等价于 x + width 的值
    rect.right = rect.x + rect.width

    // 矩形区域的最上侧坐标，等价于 y 的值
    rect.top = rect.y

    // 矩形区域的最下侧坐标，等价于 y + height 的值
    rect.bottom = rect.y + rect.height

    // 矩形区域的中心 x 坐标
    rect.cx = rect.x + rect.width / 2

    // 矩形区域的中心 y 坐标
    rect.cy = rect.y + rect.height / 2
    return rect
}

// 返回默认矩形，防止报错
function defaultRectBox() {
    return {
        x: 0,
        y: 0,
        width: 0,
        height: 0
    }
}

// 获取所有连线信息, d.pathdata
function getLinkPathData(links) {
    var data = [],
        path = '',
        i

    for (i = 0; i < links.length; i++) {
        path = links[i].pathdata || ''
        if (!path) {
            path = 'M0,0z'
        }
        data.push(path)
    }
    return data
}

// 获取所有节点path
function getNodePathData(nodes) {

    var data = []
        //  多次展开, 会乱掉
    nodes.forEach(function(d) {
        data.push('M' + d.true_y + ',' + d.true_x + 'h' + d.true_width + 'v' + d.true_height + 'h-' + d.true_width + 'z')
    })
    return data
}

// 把path列表转化为字符串
function pathToString(pathSegment) {

    pathSegment = pathSegment || this
    if (typeof pathSegment == 'string') return pathSegment
    if (pathSegment instanceof Array) {
        pathSegment = flatten(pathSegment)
        return pathSegment.join(',').replace(/,?([achlmqrstvxz]),?/gi, '$1')
    }
}

// 处理嵌套数据
function flatten(arr) {
    var result = [],
        length = arr.length,
        i
    for (i = 0; i < length; i++) {
        if (arr[i] instanceof Array) {
            result = result.concat(flatten(arr[i]))
        } else {
            result.push(arr[i])
        }
    }
    return result
}

// 关闭所有展开的子节点
function closeAllExpander(d) {
    if (d.children) {
        d._children = d.children //将该子节点保存到 _children
        d.children.forEach(closeAllExpander)
        d.children = null //将子节点设置为null
    }
}


// 递归改变子节点数据
function changeChildData(d, child_data) {
    for (var key in child_data) {
        d[key] = child_data[key]
    }
    if (d.children) {
        d.children.forEach(function(child) {
            changeChildData(child, child_data)
        })
    } else if (d._children) {
        d._children.forEach(function(child) {
            changeChildData(child, child_data)
        })
    }
}

var Tree = function(option) {
    option = typeof option === 'object' ? option : {}
    var self = {} // 配置
    var svg = {} // 返回对象
    if (!option.el) {
        throw '请选择父元素'
    }

    if (JSON.stringify(option.data || {}) === '{}') {
        throw '请输入data数据'
    }

    self.el = option.el // svg父级选择器
    self.parent = d3.select(self.el) // 父级节点
        // self.data = option.data || {}; // 数据, 树形结构数据
    self.token = option.token || '' // 唯一识别码，用于多个svg的识别
    self.suffix = self.token && '_' + self.token || '' // 唯一后缀，用于页面里面有多个svg的情况，防止id重复
    self.width = option.width || 1500 // 整个svg的宽度
    self.height = option.height || 700 // 整个svg的宽度
    self.nodeWidth = option.nodeWidth || 250 // 节点宽度
    self.nodeHeight = option.nodeHeight || 50 // 节点宽度
    self.nodePathWidth = option.nodePathWidth || 100 // 节点之间线段宽度
    self.rootFontSize = option.rootFontSize || 18 // 根节点字体
    self.childFontSize = option.childFontSize || 14 // 其它节点字体
    self.duration = option.duration || 300 // 动画过渡时间
    self.pathPadding = option.pathPadding || 5 // 文字边框padding
    self.radius = option.radius || 2 // 文字边框path圆角
    self.expandWidth = option.expandWidth || 13 // 圆形展开按钮直径
    self.editCircleWidth = option.editCircleWidth || 14 // 圆形编辑按钮宽度
    self.zoomList = option.zoomList || [20, 50, 80, 100, 120, 150, 200] // 允许缩放倍数, 默认值是100, 在中间
    self.defaultZoomIndex = option.defaultZoomIndex || ((self.zoomList.length + 1) / 2 - 1) // 默认缩放索引，应该是100的位置
    self.scrollStep = option.scrollStep || 80 // 滚动条滚动大小
    self.originX = option.x || 150 // 默认位置 x
    self.originY = option.y || self.height / 2 // 默认位置 y
    self.showSort = option.showSort || 0 // 是否显示排序
    self.nameMaxLength = option.nameMaxLength || 0 // 节点名字显示的最大长度, 超过时显示 ...
        /* 额外关联字段
         * 用来确认和图谱关联的其他表的字段信息
         * 用于编辑、复制、粘贴时和原来的节点同步数据
         * 例如：rule_code, word_code这些字段
         * */
    self.extraFields = option.extraFields || []

    /* 继承的属性
     * 子节点的属性和父节点的相同，剪切和粘贴时使用 */
    self.inheritFields = option.inheritFields || []

    // 样式相关
    self.style = {} // 样式
    self.style.root = { path: { fill: '#24C79E', stroke: '#24C79E' }, text: { fill: '#F1F2F5', 'stroke-width': 0 } } // 根节点样式
    self.style.node = { path: { fill: '#e6faf5', stroke: '#24C79E' }, text: { fill: '#24c79e' } } // 节点样式
    self.style.key_node = { path: { fill: '#f5f5f5', stroke: '#24C79E' }, text: { fill: '#666666' } } // 关键点样式
    self.style.cut = { path: { fill: '#fafafa', stroke: '#24C79E' }, text: { fill: '#cccccc' } } // 剪切样式
    self.style.cut_key = { path: { fill: '#f6fdfc', stroke: '#24C79E' }, text: { fill: '#A9EFDE' } } // 剪切样式
    self.style.copy = self.style.cut // 复制样式
    self.style.copy_key = self.style.cut_key // 复制样式

    // 复制和粘贴样式相同

    // 合并样式
    function addOptionStyle(optionStyle) {

        var i = ''
        for (i in self.style) {
            var nodeStyleName = optionStyle[i]
            if (nodeStyleName) {
                Object.assign(self.style[i], nodeStyleName)
            }
        }
    }

    if (option.style) {
        addOptionStyle(option.style || {})
    }


    self.editFunc = option.editFunc || null // 右键和点击编辑按钮触发的事件
    self.ajaxGet = option.getFunc || null // 获取节点数据的函数
    self.changeSortFunc = option.changeSortFunc || null // 序号的点击事件

    // 缩略图
    self.minimap = {}
    self.minimap.el = option.miniEl || ''
    self.minimap.parent = self.minimap.el ? d3.select(self.minimap.el) : null
    self.minimap.width = option.minimapWidth || 200 // 缩略图区域宽度
    self.minimap.height = option.minimapHeight || 120 // 缩略图区域高度
    self.minimap.padding = option.minimapPadding || 10
    self.minimap.draging = false // 缩略图是否在拖拽状态
    self.hasMini = option.hasMini || false // 是否有缩略图

    // 工具栏, 数组或着字符串
    self.toolbar = option.toolbar || {}
    self.toolbar.el = self.toolbar ? self.toolbar.el : null // 工具栏dom元素
        // 工具栏选项 ['origin', 'zoom']
        // 工具栏选项必须指定
    self.toolbar.options = self.toolbar ? self.toolbar.options : null

    // 缩略图父级元素存在, 或者传入hasMini，则创建缩略图
    if (self.minimap.parent && self.minimap.parent.node()) {
        self.hasMini = true
    }

    svg.el = self.el // svg父级选择器
    svg.parent = self.parent // 父级节点
        // svg.$zoomIn = d3.select(option.zoom_in);  // 缩小按钮
        // svg.$zoomOut = d3.select(option.zoom_out);  // 放大按钮
        // svg.$resetZoom = d3.select(option.resetZoom);  // 缩放还原

    svg.data = option.data || {} // 数据, 树形结构数据

    svg.data.x0 = 0
    svg.data.y0 = 0

    svg.token = self.token
    svg.zoomIndex = self.defaultZoomIndex // 当前缩放的索引


    svg.minimap = {
        el: self.minimap.el,
        parent: self.minimap.parent
    }

    /* point.edit
     * point.cut
     * point.copy */
    svg.point = {} // 用于存放当前编辑的点的数据

    // 当前页面里面是否有point.edit里面的数据
    svg.dont_has_edit = false

    // expand_width = 13;
    // path_padding = self.pathPadding;
    // radius = self.radius;
    // 性别code和汉字对照
    self.sexDict = {
        'none': '无',
        'man': '男',
        'woman': '女'
    }

    // 初始化dom
    function init_dom() {
        // svg
        svg.own_svg = d3.select(self.el)
            .append('svg')
            .attr(':xmlns', 'http://www.w3.org/2000/svg')
            .attr(':xmlns:xlink', 'http://www.w3.org/1999/xlink')
            .attr('id', 'svg_main' + self.suffix)
            .attr('width', self.width)
            .attr('height', self.height)
            // 用来处理缩放
        svg.scale_g = svg.own_svg.append('g').attr('id', 'scale_g' + self.suffix)
            // 用来移动等操作
        svg.atlas_g = svg.scale_g.append('g').attr('id', 'atlas_g' + self.suffix)
            .attr('transform', 'translate(' + self.originX + ',' + self.originY + ')') // 默认位置
        svg.ele = svg.atlas_g
            // 添加一个分组，用于存放连线path
        svg.links = svg.ele.append('g').attr('class', 'link_connect_group')
    }

    // 初始化缩略图
    function init_minimap() {
        // 有缩略图，但是父级不存在, 创建一个div元素
        if (self.hasMini && !(self.minimap.parent)) {
            svg.minimap.parent = svg.parent
                .append('div')
                .classed('minimap-div', true)
        }

        svg.minimap.svg = svg.minimap.parent
            .append('svg')
            .attr('id', 'svg_mini' + self.suffix)
            .attr('width', '100%')
            .attr('height', '100%')
            // mousedown, mousemove, mouseup实现伪拖拽效果
            .on('mousedown', function() {
                self.minimap.draging = true
                d3.select(this).classed('grab', true)
                    // $(this).addClass('grab')
            })
            .on('mousemove', function() {
                if (self.minimap.draging) {
                    moveView()
                }
            })
            .on('mouseup', function() {
                self.minimap.draging = false
                d3.select(this).classed('grab', false)
            })
            .on('click', function() {
                moveView()
            })
            .on('contextmenu', function() {
                // 屏蔽鼠标右键
                d3.event.preventDefault()
            })
        svg.minimap.minimap = svg.minimap.svg
            .append('g')
            .attr('class', 'minimap')
        getIndexPreviewer()
    }


    // 初始化工具条
    function init_toolbar() {
        if (self.toolbar.options && self.toolbar.options.length > 0) {
            var has_tool = false
            if (self.toolbar.el) {
                self.toolbar.parent = d3.select(self.toolbar.el)
            } else {
                self.toolbar.parent = svg.parent
                    .append('div')
                    .classed('tool', true)
            }
            // 工具条内容
            // 回到原点的按钮
            if (self.toolbar.options.indexOf('origin') >= 0) {
                has_tool = true
                self.toolbar.origin = self.toolbar.parent
                    .append('div')
                    .classed('tool-location', true)
                    .append('div')
                    .classed('local-root', true)
                    .attr('id', 'go_root' + self.suffix)
                    .attr('title', '原点')
                    .on('click.czoom', null)
                    .on('click.czoom', svg.go_root)
            }
            // 放大缩小按钮
            if (self.toolbar.options.indexOf('zoom') >= 0) {
                has_tool = true
                var slider = self.toolbar.parent
                    .append('div')
                    .classed('tool-slider', true)
                    .append('div')
                    .classed('slider-up-down', true)
                self.toolbar.zoom_in = slider
                    .append('div')
                    .classed('slider-add', true)
                    .attr('title', '放大')
                    .on('click.czoom', null)
                    .on('click.czoom', svg.zoom_in)
                self.toolbar.zoom_out = slider
                    .append('div')
                    .classed('slider-reduce', true)
                    .attr('title', '缩小')
                    .on('click.czoom', null)
                    .on('click.czoom', svg.zoom_out)
            }
            if (!has_tool) {
                throw 'toolbar 内容不对'
            }
        }
    }

    // 鼠标滚轮事件
    function eventScroll() {
        // 得到鼠标滚轮偏移量
        // 火狐 向下为 正数， 其余浏览器 向下为负数
        // 规定 鼠标滚轮向下滑动时，取负值
        var wheelStep
            // wheelStep = d3.event.wheelDelta && d3.event.wheelDelta || d3.event.deltaY / 3;
        if (d3.event.wheelDelta) {
            wheelStep = d3.event.wheelDelta > 0 && 1 || -1
        } else {
            wheelStep = d3.event.deltaY > 0 && -1 || 1
        }
        // 滚轮向下， 图形上移
        var transform = d3.transform(svg.ele.attr('transform'))
        var translate = transform.translate
            // 获取当前高度
            // var nowHeight = svg.node().getBoundingClientRect().height || 0;
            // nowHeight = Math.ceil(nowHeight / 10);
            // step = nowHeight > svg.scrollStep ? nowHeight : svg.scrollStep;
        transform.translate = [translate[0], translate[1] + wheelStep * self.scrollStep]
        svg.ele
            // .transition()
            // .duration(100)
            // .transition().duration(100).ease('linear')
            .attr('transform', transform.toString())
        resetMiniRect()
    }


    // 点击svg视图，拖拽效果
    function dragMoveSvg() {
        var transform = d3.transform(svg.ele.attr('transform'))
        var translate = transform.translate
        transform.translate = [translate[0] + d3.event.dx || 0, translate[1] + d3.event.dy || 0]
        svg.ele.attr('transform', transform.toString())
        if (self.hasMini) {
            resetMiniRect()
        }
    }

    // 拖拽事件
    var drag = d3.behavior.drag()
        .origin(function() {
            // 设置偏移原点
            return { x: 0, y: 0 }
        })
        .on('drag', dragMoveSvg)

    var tree = d3.layout.tree()
        .size([self.width, self.height - 200])
        .nodeSize([50, self.nodeWidth]) // 设置节点大小, 节点位置[高, 宽]
        .separation(function(a, b) {
            // 相邻节点计算
            return (a.parent === b.parent ? 1 : 2)
        })

    // svg添加事件
    function addEvents() {
        // 滚动条
        svg.own_svg.on(getWheelEventName(), eventScroll)
            .call(drag)
            .on('contextmenu', function() {
                // 屏蔽鼠标右键
                d3.event.preventDefault()
            })
            // .on('drag', dragMoveSvg)
    }

    /* svg的编辑函数
     * 展开和各种按钮 */

    // 获取text文本框的实际显示宽和高
    function getTextBox(d) {

        // 是否重新获取宽度
        var isNew = arguments[1] && arguments[1] || false

        if (isNew || !d.box_width0) {
            var text = svg.ele.select('#node_text_' + d.id + self.suffix).node()
            var box = getBoundaryBox(text)

            // 存放文本宽高信息, x和y无用
            d.box_x0 = box.x
            d.box_y0 = box.y
            d.box_width0 = box.width
            d.box_height0 = box.height
        } else {
            box = {
                x: d.box_x0,
                y: d.box_y0,
                width: d.box_width0,
                height: d.box_height0
            }
        }
        return box
    }

    // 获取节点（最大）宽度信息
    function get_text_width(d) {

        if (d.max_sibling_width) {
            return d.max_sibling_width
        } else {
            return getTextBox(d).width
        }

    }

    // 展开按钮触发之前, 从后台动态获取数据
    function startToggleExpander(d) {
        svg.dont_has_edit = false
        svg.point.edit = d
            // 如果有子节点，当前没有子节点数据
        if (d.has_child && !(d._children || d.children)) {
            if (self.ajaxGet) {
                self.ajaxGet(d, 'get_child', toggleExpander)
            }
        } else {
            toggleExpander(d)
        }
    }


    // 切换开关， 点击左边圆形， 展开子节点
    function toggleExpander(d) {

        var node = svg.ele.select('#expander_' + d.id + self.suffix)

        // 不存在子节点，隐藏按钮
        if (!d.has_child) {
            d3.select('#expander_' + d.id + self.suffix).style('display', 'none')
        } else {
            var thisNode = node
            var parent = node.node().parentNode
                //如果有子节点， 关闭节点
            if (d.children) {
                closeAllExpander(d)
                    // d._children = d.children; //将该子节点保存到 _children
                    // d.children = null;  //将子节点设置为null
                thisNode.selectAll('.cir-in').attr('d', expandElbowClose(d))
                    // d3.select(parent).attr("class", parentClassName);
                d3.select(parent).classed('node-open', false)
            } else {
                //如果没有子节点，展开节点
                d.children = d._children //从 _children 取回原来的子节点
                d._children = null //将 _children 设置为 null
                thisNode.selectAll('.cir-in').attr('d', expandElbowOpen(d))
                d3.select(parent).classed('node-open', true)
                    // d3.select(parent).attr("class", parentClassName + " " + "node-open");
            }
            svg.draw(d)
        }
    }

    // 展开节点和关闭时的子节点位置
    function transformEnter(d) {
        var y = 0
        if (d.source_parent) {
            y = d.y0 + getTextBox(d.parent).width + self.pathPadding * 2 - 20
        } else {
            y = d.y0
        }
        // 下方如写成(去除y坐标的扩号)，会导致子元素向右飞出 "translate(" + y + path_padding * 2 + "," + source.x + ")"
        return 'translate(' + (y + self.radius * 2) + ',' + d.x0 + ')'
    }

    // 节点取消加粗
    function quitNodeClick() {
        // 节点取消加粗
        svg.ele.selectAll('.rect-path')
            .attr('class', 'rect-path')
            .attr('stroke-width', 0)
    }


    // 画出展开按钮
    function drawToggleExpanderButton(enterNodes) {
        var leftCircle = enterNodes.insert('g', ':first-child')
            .attr('id', function(d) {
                return 'expander_' + d.id + self.suffix
            })
            .attr('class', 'node-g-expander out-button')
            .attr('transform', function() {
                // 判断是否有展开按钮
                // if (d.parent && d.has_child) {
                // y = -(path_padding + radius) - expand_width / 2;
                // y = - radius - path_padding - expand_width + 1 / 2;  // 加上0.5去除边框影响
                var y = -self.radius - self.pathPadding - self.expandWidth + 1 // 加上0.5去除边框影响
                    // }
                return 'translate(' + y + ',' + 0 + ')'
            })
            .style('display', function(d) {
                // 是否隐藏按钮
                if (!(d.parent && d.has_child)) {
                    return 'none'
                } else {
                    return ''
                }
            })
            // 点击展开按钮，展开子节点
            .on('click', startToggleExpander)

        // 画圆形
        leftCircle.append('path')
            .attr('class', 'cir-out')
            .attr('d', expandElbow)
            .attr('fill', 'white')
            .attr('stroke', 'gray')


        // 画圆中间 + 或者 -
        leftCircle.append('path')
            .attr('class', 'cir-in')
            .attr('d', function(d) {
                if (d.children) {
                    return expandElbowOpen(d)
                } else {
                    return expandElbowClose(d)
                }
            })
            .attr('fill', 'none')
            .attr('stroke', 'gray')

        return leftCircle
    }

    // 画出编辑按钮
    function drawEditCircle(editNodes) {
        var edit_circle = editNodes.append('g')
            .attr('id', function(d) {
                return 'edit_button_' + d.id + self.suffix
            })
            .attr('class', 'node-g-edit out-button')
            .attr('transform', function(d) {
                var box = getTextBox(d)
                return 'translate(' + (box.width + self.pathPadding * 2 - self.pathPadding + self.radius + 5) + ',' + 0 + ')'
            })
            .on('click', function(d) {
                d3.event.preventDefault()
                    // 其他子节点取消加粗
                quitNodeClick()
                d3.select(this.parentNode).selectAll('.rect-path')
                    .attr('stroke-width', 1)
                svg.dont_has_edit = false
                svg.point.edit = d
                if (self.editFunc) {
                    var out_d = Object.assign({}, d)
                    var event = {
                        clientX: d3.event.clientX,
                        clientY: d3.event.clientY
                    }
                    self.editFunc(out_d, event)
                }
            })


        // 一个大圆里面，画出三个小圆
        edit_circle.append('circle')
            .attr('class', 'edit-cir')
            .attr('cx', self.editCircleWidth / 2)
            .attr('cy', 0)
            .attr('r', self.editCircleWidth / 2)
            .attr('fill', '#AFAFAF')
            .style('fill-opacity', 0)
            .style('stroke-opacity', 0)
            .style('stroke-width', 0)


        edit_circle.append('circle')
            .attr('class', 'small-cir')
            .attr('cx', self.editCircleWidth / 2 - 3)
            .attr('cy', 0)
            .attr('r', 1)
            .attr('fill', '#FFF')
            .attr('stroke', '#FFF')
            .style('stroke-opacity', 0)
            .style('stroke-width', 0)
            .style('fill-opacity', 0)


        edit_circle.append('circle')
            .attr('class', 'small-cir')
            .attr('cx', self.editCircleWidth / 2)
            .attr('cy', 0)
            .attr('r', 1)
            .attr('fill', '#FFF')
            .attr('stroke', '#FFF')
            .style('stroke-opacity', 0)
            .style('stroke-width', 0)
            .style('fill-opacity', 0)

        edit_circle.append('circle')
            .attr('class', 'small-cir')
            .attr('cx', self.editCircleWidth / 2 + 3)
            .attr('cy', 0)
            .attr('r', 1)
            .attr('fill', '#FFF')
            .attr('stroke', '#FFF')
            .style('stroke-opacity', 0)
            .style('stroke-width', 0)
            .style('fill-opacity', 0)

        return edit_circle
    }

    // 获取名字的具体内容
    function getNameContent(d) {
        if (d.name) {
            var nameLength = d.name.length
            if (self.nameMaxLength && nameLength > self.nameMaxLength) {
                return d.name.slice(0, self.nameMaxLength - 1) + '...'
            } else {
                return d.name
            }
        }
    }

    // 添加节点主体内容，增加path和text
    function addNodeContent(node) {

        node.append('title').classed('show-name', true).text(function(d) {
            return d.name
        })

        node
            .append('text')

        .attr('dx', function(d) {
                return (d._children ? -50 + 100 / 2 : -50 + 100 / 2)
            })
            .attr('dy', function(d) {
                return (d.parent ? self.childFontSize : self.rootFontSize) / 2 - 2
            })
            .attr('class', function(d) {
                return d.parent ? 'show-text text-child' : 'show-text text-root'
            })
            .attr('text-rendering', 'geometricPrecision') // 修正字体缩放问题
            .text(function(d) {
                return getNameContent(d)
            })
            .attr('id', function(d) {
                return 'node_text_' + (d.id || 0) + self.suffix
            })
            .attr('data-id', function(d) {
                return d.id || ''
            })
            .attr('data-code', function(d) {
                return d.code || ''
            })
            .attr('data-father_code', function(d) {
                return d.father_code || ''
            })

        .attr('data-has_child', function(d) {
                return d.has_child || ''
            })
            .attr('fill', function(d) {
                return getNodeTextFill(d)
            })
            .style('font-size', function(d) {
                return (d.parent ? self.childFontSize : self.rootFontSize)
            })
            .style('fill-opacity', 0)


        // 画边框
        var text_path
        text_path = node.insert('path', 'text')
            .attr('id', function(d) {
                return 'text_rect_' + d.id + self.suffix
            })
            .attr('class', 'rect-path')
            .attr('d', borderElbow)
            .attr('fill', function(d) {
                return getNodePathFill(d)
            })
            .attr('stroke', function(d) {
                if (d.is_key_point) {
                    return self.style.node.path.stroke
                } else {
                    return self.style.key_node.path.stroke
                }
            })
            .attr('stroke-width', 0)
            .style('fill-opacity', 0)
            .attr('stroke-opacity', 0)
        return text_path
    }

    // 右上角添加排序序号 ①②③④
    function addSortCircle(node) {
        var rightCircle = node.append('g')
            .attr('id', function(d) {
                return 'right_circle_' + d.id + self.suffix
            })
            .attr('class', 'sort-g')
            .on('click', function(d) {
                svg.dont_has_edit = false
                svg.point.edit = d
                if (self.changeSortFunc) {
                    self.changeSortFunc(d)
                }
            })
            .attr('transform', function(d) {
                var box = getTextBox(d)
                    // var x = box.width + self.pathPadding + self.radius + (self.pathPadding + self.radius) / 2
                var x = box.width + self.pathPadding + self.radius
                var y = -(box.height - (self.pathPadding + self.radius) / 2)
                return 'translate(' + x + ', ' + y + ')'
            })


        rightCircle.append('title')
            .text('修改排序')

        rightCircle
            .append('circle')
            // .attr("class", "edit-cir")
            .attr('cx', function() {
                // var box = getTextBox(d)
                // return box.width + self.pathPadding + 2
                return 0
            })
            .attr('cy', function() {
                // var box = getTextBox(d)
                // return -(box.height / 2 + self.pathPadding + 2)
                return 0
            })
            .attr('r', self.pathPadding + 2)
            .attr('fill', '#24C79E')
            .style('stroke-width', 0)


        rightCircle.append('text')
            .classed('sort-text', true)
            .attr('text-rendering', 'geometricPrecision') // 修正字体缩放问题
            .attr('id', function(d) {
                return 'sort_circle_' + d.id + self.suffix
            })
            .attr('dx', function() {
                // var box = getTextBox(d)
                // return box.width + self.pathPadding - self.radius
                return -(self.pathPadding + self.radius + 1) / 2
            })
            .attr('dy', function() {
                // var box = getTextBox(d)
                // return -(box.height / 2 + self.pathPadding) + self.radius + 1
                // return -(box.height / 2 + self.pathPadding) + self.radius + 1
                return (self.pathPadding + self.radius + 2 + 1) / 2
            })
            .text(function(d) {
                return d.sort || 0
            })
            .attr('fill', '#FFFFFF')

    }

    // 获得真实坐标和宽高
    function getTrueWidthAndHeight(nodes) {
        var box
            // 此处d.x, d.y 是在原点时的数据,未改变
        nodes.each(function(d) {
            box = getTextBox(d)
            d.true_width = box.width + self.pathPadding * 2 + self.radius + self.radius
            d.true_height = box.height + self.pathPadding * 2 + self.radius + self.radius
            d.true_x = d.x - d.true_height / 2
            d.true_y = d.y + (-self.pathPadding - self.radius) - 20
        })
    }


    /* 连线相关 */

    // 节点之间连接线, 绝对定位
    function elbow(d) {
        var y = d.source.y + getTextBox(d.source).width - 20
        var h1 = 0
        if (d.depth > 0 && svg.depthWidth[d.depth - 1]) {
            // if (d.source.max_sibling_width) {
            h1 = (d.source.y + svg.depthWidth[d.depth - 1] || y) + 20
                // h1 = (d.source.y + d.source.max_sibling_width || y) + 20
        } else {
            h1 = (y + (d.target.y - (self.pathPadding + self.radius) - y) / 2)
        }

        d.pathdata = 'M' + (y + self.pathPadding * 2 - self.pathPadding + self.radius) + ',' + d.source.x
            // + "H" + (y + (d.target.y - (path_padding + radius) - y) / 2)
            +
            'H' + h1 +
            'V' + d.target.x +
            'H' + (d.target.y - (self.pathPadding + self.radius) - 20)
        return d.pathdata
    }

    // 画出节点边框
    function borderElbow(d) {
        // 旧名字和新名字不相同， 重新计算宽度
        var isNew = !!(d.old_name && d.old_name !== d.name)
        d.old_name = d.name
        var box = getTextBox(d, isNew)
        return 'M' + (-self.pathPadding - self.pathPadding) + ',' + (-(box.height / 2 + self.pathPadding + self.radius)) // 画笔起点
            +
            'h' + (box.width + self.pathPadding * 4) // 上边
            +
            'a' + self.radius + ',' + self.radius + ',0,0,1,' + self.radius + ',' + self.radius // 右上圆角  "a5,5,0,0,1,5,5"
            +
            'v' + (self.pathPadding + box.height + self.pathPadding) // 右边
            +
            'a' + self.radius + ',' + self.radius + ',0,0,1,' + (-self.radius) + ',' + self.radius // 右下圆角  "a5,5,0,0,1,-5,5"
            +
            'h' + ('-' + (box.width + self.pathPadding * 4)) // 下边
            +
            'a' + self.radius + ',' + self.radius + ',0,0,1,' + (-self.radius) + ',' + (-self.radius) // 左下圆角  "a5,5,0,0,1,-5,-5"
            +
            'v' + '-' + (self.pathPadding + box.height + self.pathPadding) // 左边
            +
            'a' + self.radius + ',' + self.radius + ',0,0,1,' + self.radius + ',' + (-self.radius) // 左上圆角  "a5,5,0,0,1,5,-5"
            +
            'z' // 闭合曲线
    }


    // 画出圆形展开开关
    function expandElbow() {
        var radii = self.expandWidth / 2 //半径
        return 'M' + radii + ',0' +
            'A' + radii + ',' + radii + ',0,1,1,' + (-radii) + ',0' +
            'A' + radii + ',' + radii + ',0,1,1,' + radii + ',0'
    }

    // 展开按钮  展开状态  ⊖
    function expandElbowOpen(d) {
        var radii = self.expandWidth / 2 - 2
        return d.children ? 'M' + (-radii) + ',0L' + radii + ',0' : ''
    }

    // 展开按钮  关闭状态  ⊕
    function expandElbowClose(d) {
        var radii = self.expandWidth / 2 - 2
        return (d._children || d.has_child) ? 'M' + (-radii) + ',0L' + radii + ',0M0,' + (-radii) + 'L0,' + radii + '' : ''
    }

    // 获取节点path的长度
    function getPathWidth(name, font_size) {
        if (name) {
            return self.pathPadding + getByteLen(name) / 2 * font_size + self.pathPadding
        }
    }

    // 展开，收起时画的线
    function transitionElbow(d) {
        return 'M' + d.source.y + ',' + d.source.x +
            'H' + d.source.y +
            'V' + d.source.x +
            'H' + d.source.y
    }

    /* 结束svg交互函数 */


    /* 缩略图相关函数 */

    // 初始化minimap
    function getIndexPreviewer() {

        // 节点
        svg.minimap.item = svg.minimap.minimap.append('path')
            // .attr('id', 'miniNode')
            .attr('id', 'miniNode' + self.suffix)
            .attr('class', 'mini-node')
            .attr('fill', '#E7E7E7')

        // 连线
        svg.minimap.link = svg.minimap.minimap.append('path')
            .attr('id', 'miniLink')
            .attr('class', 'mini-link' + self.suffix)
            .attr('stroke', '#24C79E')
            .attr('stroke-width', 1)
            .attr('fill', 'none')

        // 红色方框
        svg.minimap.rect = svg.minimap.minimap.append('path')
            .attr('id', 'mini_rect' + self.suffix)
            .attr('d', 'M50, 25h100v50h-100z')
            // .attr('d', '')
            .attr('stroke', 'red')
            .attr('fill', 'none')
            .attr('stroke-width', '1%')
    }

    // 移动缩略图，同时移动主图形
    function moveView() {
        /*
         * 移动时，
         * 1.先获取svg_mini点击点的位置 p1
         * 2.把p1转化为svg_mini下面子坐标系(g)中的位置 p2，这里p2 = p1
         * 3.p2的位置相当于atlas_g中点的位置，即是这个点在atlas_g父级坐标系（scale_g）中的位置 p3
         * 4.获取svg_main的中心点，转化为atlas_g父级坐标系（scale_g）中的位置 g1
         * 5.获取atlas_g当前translate
         * 6.计算移动后的坐标，transform: [translate[0] - (p3.x - g1.x), translate[1] - (p3.y - g1.y)]
         * 7.把transform坐标添加到atlas_g
         * */

        var mini, point, sp, atlasPoint, point2
        mini = svg.minimap.svg.node()

        // 获取点击点在svg_mini坐标系中的位置
        point = mini.createSVGPoint()
        sp = d3.mouse(mini)
        point.x = sp[0]
        point.y = sp[1]

        // 获取点击点在svg_mini的g的坐标系中的位置
        atlasPoint = getMatrixPoint(point, mini, svg.minimap.item.node())
            // svg_mini下面的g的点的位置，相当于atlas_g的点的位置
            // atlas_g的点的位置 转化为 scale_g坐标系中的位置
        point2 = getMatrixPoint(atlasPoint, svg.ele.node(), svg.scale_g.node())
            // 移动图谱
        moveAtlas(point2)
    }


    // 移动图谱
    function moveAtlas(point) {

        var transform = d3.transform(svg.ele.attr('transform'))
        var translate = transform.translate
            // var scale = d3.transform(svg.attr('transform')).scale;
            // 获取需要移动的坐标: g的坐标 - (点的坐标 - 中心点坐标)
            // var tx, ty;
            // tx = translate[0] - (point.x - svg.centerX) - 200;
            // ty = translate[1] - (point.y - svg.centerY);
        transform.translate = [translate[0] - (point.x - svg.atlasX) - 200, translate[1] - (point.y - svg.atlasY)]
        svg.ele
            // .transition()
            // .duration(100)
            // .transition().duration(300).ease('linear')
            //     .attr('transform', 'translate(' + tx + ',' + ty + ') scale(' + scale + ')');
            .attr('transform', transform.toString())
            // 移动缩略图红色矩形
        resetMiniRect()
    }

    // 画预览图、缩略图
    function drawPreviewer(nodes, links) {

        // 等主界面加载完再生成缩略图
        setTimeout(
            resetMinimap, self.duration
        )

        // 获取所有连线信息, d.pathdata
        svg.minimap.link.attr('d', pathToString(getLinkPathData(links)))

        // 获取所有节点的位置信息
        svg.minimap.item.attr('d', pathToString(getNodePathData(nodes)))
    }

    // 重设缩略图的显示部分
    function resetMinimap() {
        // 给svg对象增加中心点坐标
        setAtlasCenter()

        var svg_box = getBoundaryBox(svg.ele.node())
            // 缩略图位置信息
            // if (!(svg_box.height < self.minimap.height && svg_box.width < self.minimap.width)) {
            //     // svg的宽和高大于minimap的宽和高
            //     // viewBox的x, y是视窗的移动，即看上去图形向相反方向移动
            //     // svg.minimap.svg.attr('viewBox', [
            //     //     svg_box.x - self.minimap.padding - 0.5,
            //     //     svg_box.y - self.minimap.padding - 0.5,
            //     //     svg_box.width + self.minimap.padding * 2 + 1,
            //     //     svg_box.height + self.minimap.padding * 2 + 1
            //     // ].join(" "));
            //
            //     // 重画矩形框
            //     resetMiniRect();
            // }
            // svg的宽和高大于minimap的宽和高
            // viewBox的x, y是视窗的移动，即看上去图形向相反方向移动
        svg.minimap.svg.attr('viewBox', [
                svg_box.x - self.minimap.padding - 0.5,
                svg_box.y - self.minimap.padding - 0.5,
                svg_box.width + self.minimap.padding * 2 + 1,
                svg_box.height + self.minimap.padding * 2 + 1
            ].join(' '))
            // 重画矩形框
        resetMiniRect()
    }

    // 重画缩略图红色矩形
    function resetMiniRect() {
        if (self.hasMini) {
            svg.minimap.rect.attr('d', getMiniRect_d())
        }
    }

    /** 画出缩略图的红色框, 重画也使用这个
     *  获取svg和g的位置关系，算出两者相交部分为矩形区域
     *  使用getBoundingClientRect()获取
     * @return {string} 表示矩形的path的属性d的值
     */
    function getMiniRect_d() {
        var newBox = getNewRectBox()
            // 未加移动位置
        return 'M' + newBox.x + ',' + newBox.y + 'h' + newBox.width + 'v' + newBox.height + 'h-' + newBox.width + 'z'
    }


    // 获取新的矩形位置信息
    function getNewRectBox() {
        var svg_box = svg.own_svg.node().getBoundingClientRect()
        var g_box = svg.ele.node().getBoundingClientRect()

        // 获取相交部分
        var box = intersect(svg_box, g_box)
            // 获取实际坐标到atlas_g的变换矩阵
        var matrix = svg.ele.node().getScreenCTM().inverse()
            // 把实际坐标系转化为svg坐标系
        return transformBox(box, matrix)
    }

    /** 按照转化矩阵，转换坐标, 实际是转换四个顶点的坐标
     * @param box 需要转化的box
     * @param matrix, 转化矩阵 例如: [1, 0, 0, 1, 0, 0]
     * @return {*}
     */
    function transformBox(box, matrix) {
        var xMin = Number.MAX_VALUE,
            xMax = -Number.MAX_VALUE,
            yMin = Number.MAX_VALUE,
            yMax = -Number.MAX_VALUE
        var oldp = [
            [box.x, box.y],
            [box.x + box.width, box.y],
            [box.x, box.y + box.height],
            [box.x + box.width, box.y + box.height]
        ]
        var rp, pt, i
            // 转换矩形四个点坐标
        for (i = 0; i < oldp.length; i++) {
            pt = svg.own_svg.node().createSVGPoint()
            pt.x = oldp[i][0]
            pt.y = oldp[i][1]
            rp = pt.matrixTransform(matrix)
            xMin = Math.min(xMin, rp.x)
            xMax = Math.max(xMax, rp.x)
            yMin = Math.min(yMin, rp.y)
            yMax = Math.max(yMax, rp.y)
        }

        box = {
            x: xMin,
            y: yMin,
            width: xMax - xMin,
            height: yMax - yMin
        }
        return box
    }

    /* 缩略图结束 */


    // 获取节点path的fill样式
    function getNodePathFill(d) {
        var fill = ''
        if (d.parent) {
            if (svg.point.cut && svg.point.cut.parent && svg.point.cut.id == d.id) {
                return d.is_key_point && self.style.copy_key.path.fill || self.style.copy.path.fill
            } else {
                fill = d.is_key_point ? self.style.node.path.fill : self.style.key_node.path.fill
            }
        } else {
            fill = self.style.root.path.fill
        }
        return fill
    }

    // 获取节点text的fill样式
    function getNodeTextFill(d) {
        var fill = ''
        if (d.parent) {
            if (svg.point.cut && svg.point.cut.parent && svg.point.cut.id == d.id) {
                fill = d.is_key_point && self.style.copy_key.text.fill || self.style.copy.text.fill
            } else {
                fill = d.is_key_point ? self.style.node.text.fill : self.style.key_node.text.fill
            }
        } else {
            fill = self.style.root.text.fill
        }
        return fill
    }


    /* 外部操作函数 */

    // 给svg对象增加中心点坐标
    function addCenterToSvg() {
        if (!(svg.centerX || svg.centerY)) {
            var svgMain = svg.own_svg.node()
            var svgRect = svgMain.getBoundingClientRect()
                // svg的中心点
            svg.centerX = (svgRect.right - svgRect.left) / 2
            svg.centerY = (svgRect.bottom - svgRect.top) / 2
        }
    }

    // 重写svg_main 到scale_g的变换矩阵
    function resetSvgToAtlasMatrix() {
        svg.svgToAtlasMatrix = svg.own_svg.node().getTransformToElement(svg.scale_g.node())
    }

    // 设置atlas父级坐标系(scale_g)中心点
    function setAtlasCenter() {
        resetSvgToAtlasMatrix()
        var point = svg.own_svg.node().createSVGPoint()
        point.x = svg.centerX
        point.y = svg.centerY
        var atlasPoint = point.matrixTransform(svg.svgToAtlasMatrix)
        svg.atlasX = atlasPoint.x
        svg.atlasY = atlasPoint.y
    }


    /** 设置Svg缩放
     *  当参数有两个时, scale = [x, y]
     *  当参数有一个且为数组时 即:x = [1, 2], scale = x
     *  当参数为一个数字时, 即 x = 1.5, scale = [x, x]
     * @param x
     * @param y
     */
    svg.set_zoom = function set_zoom(x, y) {
        var scale = []
        if (arguments.length >= 2) {
            scale = [x, y]
        } else if (arguments.length === 1) {
            if (arguments[0].isArray) {
                scale = x
            } else {
                scale = [x, x]
            }
        } else {
            scale = [1, 1]
        }
        var transform = d3.transform(svg.scale_g.attr('transform'))
        transform.scale = scale
        svg.scale_g
            .transition()
            .duration(500)
            .ease('linear')
            .attr('transform', transform.toString())

        // 重置变换矩阵
        setTimeout(setAtlasCenter, 500)
            // 重画缩略图
        setTimeout(resetMiniRect, 500)
    }

    // 缩放还原
    svg.reset_zoom = function reset_zoom() {
        if (svg.zoomIndex !== self.defaultZoomIndex) {
            svg.zoomIndex = self.defaultZoomIndex
            var transform = d3.transform(svg.svg.scale_g.attr('transform'))
            svg.set_zoom(self.zoomList[svg.zoomIndex] / 100)
        }
    }


    // 放大
    svg.zoom_in = function zoom_in() {
        if (svg.zoomIndex < self.zoomList.length - 1) {
            svg.zoomIndex += 1
        }
        svg.set_zoom(self.zoomList[svg.zoomIndex] / 100)
    }

    // 缩小
    svg.zoom_out = function zoom_out() {
        if (svg.zoomIndex > 1) {
            svg.zoomIndex -= 1
        } else if (svg.zoomIndex === 1) {
            // 最后一级应该在最下边
            svg.zoomIndex -= 1
        }
        svg.set_zoom(self.zoomList[svg.zoomIndex] / 100)
    }


    // addZoomEvents();

    function addZoomEvents() {
        // 放大
        svg.$zoomIn.on('click.czoom', null) // 清空事件
            .on('click.czoom', svg.zoom_in)
            // 缩小
        svg.$zoomOut.on('click.czoom', null)
            .on('click.czoom', svg.zoom_out)
            // 还原
        svg.$resetZoom.on('click.czoom', null)
            .on('click.czoom', svg.reset_zoom)
    }

    // 位置回归到原点
    svg.go_root = function() {
        // 起始点
        var point = getMatrixPoint(svg.localPoint, svg.own_svg.node(), svg.scale_g.node())
        var transform = d3.transform(svg.ele.attr('transform'))
        transform.translate = [point.x, point.y]
            // 移动图形
        svg.ele.attr('transform', transform.toString())
            // 移动缩略图红色矩形
        resetMiniRect()
    }

    // 添加子节点数据
    svg.addChildren = function(children) {
        var d = arguments[1] && arguments[1] || svg.point.edit
            // 把数据和节点连接起来
        svg.concatChildren(d, children)

        // 要判断是否要添加展开按钮，原来图上没有子节点需要添加子节点
        if (!d.has_child) {
            d.has_child = true
                // drawToggleExpanderButton(d3.select('#node_g_' + d.id));
            svg.ele.select('#expander_' + d.id + self.suffix).style('display', '')
            svg.ele.select('#expander_' + d.id + self.suffix).on('click', startToggleExpander)
        }
        // 展开节点
        toggleExpander(d)
    }


    /**
     * 改变当前编辑点，选择另一个点作为point.edit
     * @param data 要改变成的点的数据
     */
    svg.selectEditPoint = function(data) {
        delete svg.point.edit

        // 先判断在当前页面显示的节点里面有没有data

        var node = svg.ele.select('#node_g_' + data.id + self.suffix)
        svg.dont_has_edit = false
        if (node.node()) {
            svg.point.edit = node.datum()
        } else {
            // 递归判断节点数据
            var loopSelect = function(loopD) {
                if (loopD.id == data.id) {
                    svg.point.edit = loopD
                    return true
                } else {
                    // 循环子节点
                    var for_each = loopD.children ? loopD.children : loopD._children
                    for_each = for_each && for_each || []
                    var r = false
                    for (var i = 0; i < for_each.length; i++) {
                        var res = loopSelect(for_each[i])
                        if (res) {
                            r = true
                            break
                        } else {
                            r = false
                        }
                    }
                    return r
                }
            }

            var status = loopSelect(svg.data)
                // 如果没找到数据
            if (!status) {
                svg.dont_has_edit = true
                svg.point.edit = data
            }
        }
    }


    // 把子节点数据连接起来, 把数据保存到_children
    svg.concatChildren = function(d, children) {
        if (!d._children) {
            d._children = d.children
            d.children = null
        }
        // 拼接d._children数据
        if (d._children && children) {
            d._children = d._children.concat(children)
        } else {
            d._children = children
        }
    }

    // 编辑节点
    svg.editNode = function(data, flag) {
        console.dir(svg.point)
        let nid = data.nid;
        var d = arguments[1] && arguments[1] || svg.point.edit
        if (flag) {
            let children_data = svg.data.children
            console.log(returnedItem)
            children_data.forEach((item, index) => {
                if (nid == item.id) {
                    svg.changeNodeData(item, data)
                        // 改变节点样式
                        // svg.changeNodeStyle(d);
                    svg.draw(item)
                } else {

                }
            })
        } else {
            if (svg.dont_has_edit) {
                svg.dont_has_edit = false
                delete svg.point.edit
            } else {
                svg.changeNodeData(d, data)
                    // 改变节点样式
                    // svg.changeNodeStyle(d);
                svg.draw(d)
            }
        }

    }

    // 改变节点数据
    svg.changeNodeData = function(d, data) {
        d.name = data.name
        d.is_key_point = data.is_key_point || 0
        d.rule_code = data.rule_code
        d.man_rule_code = data.man_rule_code
        d.woman_rule_code = data.woman_rule_code
        if (data.adapter) {
            d.adapter = data.adapter || ''
        }
        self.extraFields.forEach(function(f) {
            d[f] = data[f] || ''
        })
    }

    svg.changeNodeStyle = function(d) {
        // 判断名字是否修改
        if (d.old_name !== d.name) {
            // 删除编辑后的dom元素，重绘图形
            svg.draw(d)
        } else {
            svg.ele.select('#node_text_' + d.id + self.suffix)
                .attr('fill', function(d) {
                    var fill = ''
                    if (d.parent) {
                        fill = d.is_key_point ? self.style.node.path.fill : self.style.key_node.path.fill
                    } else {
                        fill = self.style.root.path.fill
                    }
                    return fill
                })
            svg.ele.select('#text_rect_' + d.id + self.suffix)
                .attr('stroke', function(d) {
                    if (d.is_key_point) {
                        return self.style.node.text.stroke

                    } else {
                        return self.style.key_node.text.stroke
                    }
                })
                .attr('fill', function(d) {
                    var fill = ''
                    if (d.parent) {
                        fill = d.is_key_point ? self.style.node.text.fill : self.style.key_node.text.fill
                    } else {
                        fill = self.style.root.text.fill
                    }
                    return fill
                })
        }
    }


    // 重置节点样式
    svg.resetStyle = function(d) {
        d = arguments && arguments[0] || svg.point.edit
        svg.ele.select('#text_rect_' + d.id + self.suffix).attr('fill', function(d) {
            return d.is_key_point ? self.style.node.path.fill : self.style.key_node.path.fill
        })
        svg.ele.select('#node_text_' + d.id + self.suffix).attr('fill', function(d) {
            return d.is_key_point ? self.style.node.text.fill : self.style.key_node.text.fill
        })
    }


    // 剪切状态激活
    svg.activeCut = function() {
        // 重置其他节点的剪切样式
        if (svg.point.copy || svg.point.cut) {
            svg.resetStyle(svg.point.copy || svg.point.cut)
        }
        svg.point.cut = arguments && arguments[0] || svg.point.edit
        svg.resetCopyData()
        svg.changeCutStyle(svg.point.cut)
    }


    // 复制状态激活, 剪切状态和复制状态只能激活一个
    svg.activeCopy = function() {
        if (svg.point.cut || svg.point.copy) {
            svg.resetStyle(svg.point.cut || svg.point.copy)
        }
        svg.point.copy = arguments && arguments[0] || svg.point.edit
        svg.resetCutData()
        svg.changeCopyStyle(svg.point.copy)
    }

    // 重置剪切数据
    svg.resetCutData = function() {
        delete svg.point.cut
    }

    // 重置复制数据
    svg.resetCopyData = function() {
        delete svg.point.copy
    }

    // 重置剪切、复制样式和数据
    svg.removeCutAndCopy = function() {
        if (svg.point.cut || svg.point.copy) {
            svg.resetStyle(svg.point.cut || svg.point.copy)
        }
        svg.clearCutAndCopy()
    }

    // 清空样式
    svg.clearCutAndCopy = function() {
        svg.resetCutData()
        svg.resetCopyData()
    }

    // 改变剪切样式
    svg.changeCutStyle = function(d) {
        d = arguments && arguments[0] || svg.point.cut || svg.point.edit
        svg.ele.select('#text_rect_' + d.id + self.suffix).attr('fill', function(d) {
            return d.is_key_point && self.style.cut_key.path.fill || self.style.cut.path.fill
        })
        svg.ele.select('#node_text_' + d.id + self.suffix).attr('fill', function(d) {
            return d.is_key_point && self.style.cut_key.text.fill || self.style.cut.text.fill
        })
    }

    // 改变复制样式
    svg.changeCopyStyle = function(d) {
        d = arguments && arguments[0] || svg.point.copy || svg.point.edit
        svg.ele.select('#text_rect_' + d.id + self.suffix).attr('fill', function(d) {
            return d.is_key_point && self.style.copy_key.path.fill || self.style.copy.path.fill
        })
        svg.ele.select('#node_text_' + d.id + self.suffix).attr('fill', function(d) {
            return d.is_key_point && self.style.copy_key.text.fill || self.style.copy.text.fill
        })
    }

    /**
     * 粘贴剪切的节点
     * @param from 来源节点 数据,d
     * @param to 要粘贴到的节点 数据,d
     */
    svg.parse_cut = function(from, to) {
        from = arguments[0] && arguments[0] || svg.point.cut
        to = arguments[1] && arguments[1] || svg.point.edit

        deleteNodeData(from)

        closeAllExpander(from)
        from.father_code = to.code
            // 处理child_type不相同的情况
        var updateData = {} // 需要更新的数据
        if (to.child_type !== from.child_type) {
            updateData['child_type'] = to.child_type
        }

        // 需要继承的属性
        self.inheritFields.forEach(function(f) {
            if (from.hasOwnProperty(f)) {
                updateData[f] = from[f] || ''
            }
        })

        // 判断需不需要更新数据
        if (JSON.stringify(updateData) !== '{}') {
            changeChildData(from, updateData)
        }

        if (to.children || to._children) {
            if (to.children) {
                to.children.push(from)
            } else if (to._children) {
                to._children.push(from)
            }
        } else {
            to._children = []
            to._children.push(from)
        }
        to.has_child = true
        svg.resetStyle(from)
        svg.resetCutData()
            // 展开节点
        svg.draw(to)
    }

    // 删除节点数据
    function deleteNodeData(d) {
        var childName = ''
        if (d.parent.children) {
            childName = 'children'
        } else {
            childName = '_children'
        }
        var x = d.parent.children || d.parent._children

        // 删除父级相关的子节点
        for (var i = 0; i < x.length; i++) {
            var s = x[i]
                // 删除相关子节点
            if (s.id == d.id) {
                d.parent[childName].splice(i, 1)
                break
            }
        }

        if (d.parent.has_child) {
            d.parent.has_child = d.parent[childName] && d.parent[childName].length > 0
        }

        return d
    }

    /**
     * 粘贴复制的节点
     * @param copy_data 新生成的copy数据
     * @param from 来源节点
     * @param to 要粘贴的节点
     */
    svg.parse_copy = function(copy_data, from, to) {
        from = arguments[1] && arguments[1] || svg.point.copy
        to = arguments[2] && arguments[2] || svg.point.edit
        svg.resetStyle(from)
        var copy = {}
            // 复制第一层svg.copy属性，使用深拷贝
        for (var i in from) {
            copy[i] = from[i]
        }
        copy.children = null
        copy._children = null
            // copy.rule_code = copy_data.rule_code || '';
            // copy.man_rule_code = copy_data.man_rule_code || '';
            // copy.woman_rule_code = copy_data.woman_rule_code || '';

        self.extraFields.forEach(function(f) {
            copy[f] = copy_data[f] || ''
        })

        copy.id = copy_data.copy_id || 0
        copy.code = copy_data.copy_code || 0
        copy.father_code = to.code
        copy.child_type = to.child_type
        copy.is_key_point = copy_data.is_key_point !== undefined ? copy_data.is_key_point : copy.is_key_point
        if (to.children || to._children) {
            if (to.children) {
                to.children.push(copy)
            } else if (to._children) {
                to._children.push(copy)
            }
        } else {
            if (!to.has_child) {
                to._children = []
                to._children.push(copy)
                to.has_child = true
            }
        }
        to.has_child = true
        svg.resetCopyData()
        svg.draw(to)
    }

    // 删除节点
    svg.delete = function(d) {
        d = arguments[0] && arguments[1] || svg.point.edit
        deleteNodeData(d)
        svg.draw(d.parent)
    }

    // 改变sort数字
    svg.changeSort = function(text, d) {
        d = arguments[1] && arguments[1] || svg.point.edit
        d.sort = parseInt(text)
        svg.draw(d)
    }

    // // 改变sort数字
    // svg.changeSort = function (text, d) {
    //     d = arguments[1] && arguments[1] || svg.point.edit;
    //     svg.ele.select('#sort_circle_' + d.id + self.suffix).text(text);
    // }

    /**
     * 画图函数
     * 重画时，data数据其实已经被修改了
     * @param source 点击展开的点
     */
    svg.draw = function(source) {
        var data = svg.data
            // 对data的第一级元素进行排序
        if (data.children && !data.parent) {
            data.children.sort(sortNode)
        }
        // 节点
        var nodes = tree.nodes(data)
            // 连线
        var links = tree.links(nodes)
        var maxWidth = 0,
            now_width = 0

        // 本层的最大宽度
        var prevMaxWidth = 0
            // 现在层级
        var nowDepth = 0
            // 每层的最大宽度
        svg.depthWidth = []

        // 基本位置数据
        // 存储每个层级宽度最长的节点宽度
        nodes.forEach(function(d) {
            nowDepth = d.depth
            var font_size = d.depth === 0 ? self.rootFontSize : self.childFontSize
            d.text_width = getPathWidth(getNameContent(d), font_size) + (self.pathPadding + self.radius)
            var cacheWidth = svg.depthWidth[nowDepth] || 0
            prevMaxWidth = cacheWidth > d.text_width ? cacheWidth : d.text_width
            svg.depthWidth[nowDepth] = prevMaxWidth
        })

        // 重新计算节点的y坐标
        nodes.forEach(function(d) {
            maxWidth = 0
            var y
            var depth = d.depth
            if (depth > 0 && d.parent && source.parent) {
                var true_maxWidth = svg.depthWidth[d.depth - 1]
                if ((true_maxWidth + self.nodePathWidth) > self.nodeWidth) {
                    y = d.parent.y + true_maxWidth + self.nodePathWidth
                } else {
                    y = d.parent.y + self.nodeWidth
                }
            } else {
                y = d.y
            }
            d.y = y
        })


        /* 节点处理 */

        //获取节点的update部分
        var nodeUpdate = svg.ele.selectAll('.node')
            .data(nodes, function(d) {
                return d.code
            })


        //获取节点的enter部分
        var nodeEnter = nodeUpdate.enter()
            //获取节点的exit部分
        var nodeExit = nodeUpdate.exit()


        // 1.节点的 Enter 部分的处理办法
        var enterNodes = nodeEnter
            .append('g')
            .attr('id', function(d) {
                return 'node_g_' + d.id + self.suffix
            })
            .attr('class', function(d) {
                var c = 'node'
                if (!d.parent) {
                    c += ' root'
                } else if ((d.parent && (d.children || d._children))) {
                    c += ' person'
                } else {
                    c += ' person child'
                }

                if (d.depth !== 0) {
                    // 添加当前节点类型
                    c += ' atlas-default-node'
                    c += d.is_key_point ? ' atlas-key-node' : ''
                }
                return c
            })
            .attr('transform', function(d) {
                var o = {
                    x0: source.x0,
                    y0: source.y0,
                    source_parent: source.parent,
                    parent: d.parent
                }
                return transformEnter(o)
            })
            .on('click', function(d) {
                svg.dont_has_edit = false
                svg.point.edit = d
                    // 点击加粗边框
                d3.event.stopPropagation() // 阻止冒泡
                    // 其他子节点取消加粗
                quitNodeClick()
                d3.select(this).selectAll('.rect-path')
                    .attr('stroke-width', 1)
            })
            .on('contextmenu', function(d) {
                // 自定义鼠标右键菜单
                d3.event.preventDefault()
                    // 其他子节点取消加粗
                quitNodeClick()
                d3.select(this).selectAll('.rect-path')
                    .attr('stroke-width', 1)
                svg.dont_has_edit = false
                svg.point.edit = d
                if (self.editFunc) {
                    // var out_d =  Object.assign({}, d);
                    var event = {
                            clientX: d3.event.clientX,
                            clientY: d3.event.clientY
                        }
                        // self.editFunc(out_d,event)
                    self.editFunc(d, event)
                }
            })
            // 鼠标在节点悬浮时，显示编辑按钮
            .on('mouseover', function() {
                d3.select(this).selectAll('.node-g-edit circle')
                    .style('fill-opacity', 1)
                    .style('stroke-opacity', 1)
            })
            // 鼠标移出移出节点时，隐藏编辑按钮
            .on('mouseout', function() {
                d3.select(this).selectAll('.node-g-edit circle')
                    .style('fill-opacity', 0)
                    .style('stroke-opacity', 0)
            })


        // 点击其它地方，取消加粗边框
        svg.ele.select('svg').on('click', function() {
            delete svg.point.edit
            quitNodeClick()
        })

        // 添加节点主要内容
        var nodeMain = enterNodes.append('g')
            .attr('id', function(d) {
                return 'node_main_' + (d.id || 0) + self.suffix
            })
            // 添加节点主体内容，增加path和text
        addNodeContent(nodeMain)
            // 一级节点增加排序序号
        addSortCircle(nodeMain.filter(function(d) {
            return d.depth == 1 && self.showSort
        }))

        // 画展开按钮
        var leftCircle = drawToggleExpanderButton(enterNodes)

        // 画编辑按钮
        drawEditCircle(enterNodes)


        /* 节点update */

        // 2. 节点的 Update 部分的处理办法
        var updateNodes = nodeUpdate
            .transition()
            .duration(self.duration)
            .attr('transform', function(d) {
                return 'translate(' + (d.y - 20) + ',' + d.x + ')' // 把x当作y, 把y 当作x， 做成横向显示效果
            })

        /* update更新部分 */

        // 更新名字的title
        nodeUpdate.selectAll('title.show-name').text(function(d) {
            return d.name
        })

        // 更新名字
        nodeUpdate.selectAll('text.show-text')
            .text(function(d) {
                return getNameContent(d)
            })
            // 颜色
            .attr('fill', function(d) {
                return getNodeTextFill(d)
            })
            .style('fill-opacity', 1)

        // 更新一级节点序号
        updateNodes
            .filter(function(d) {
                return d.depth === 1 && self.showSort
            })
            .selectAll('.sort-g')
            // 更新位置信息
            .attr('transform', function(d) {
                var isNew = !!(d.old_name && d.old_name !== d.name)
                d.old_name = d.name
                var box = getTextBox(d, isNew)
                    // var x = box.width + self.pathPadding + self.radius + (self.pathPadding + self.radius) / 2
                var x = box.width + self.pathPadding + self.radius
                var y = -(box.height / 2 + (self.pathPadding + self.radius))
                return 'translate(' + x + ', ' + y + ')'
            })
            .selectAll('.sort-text')
            .text(function(d) {
                return d.sort || 0
            })

        // 更新节点宽度，位置
        updateNodes.selectAll('.rect-path')
            .attr('d', borderElbow)
            .attr('fill', function(d) {
                return getNodePathFill(d)
            })
            .attr('stroke', function(d) {
                if (d.is_key_point) {
                    return self.style.key_node.path.stroke
                } else {
                    return self.style.node.path.stroke
                }
            })
            .attr('stroke-opacity', 1)
            .style('fill-opacity', 1)

        // 更新编辑按钮
        updateNodes.selectAll('.node-g-edit')
            .attr('transform', function(d) {
                var box = getTextBox(d)
                return 'translate(' + (box.width + self.pathPadding * 2 - self.pathPadding + self.radius + 5) + ',' + 0 + ')'
            })

        // 更新展开按钮
        updateNodes.selectAll('.node-g-expander')
            .style('display', function(d) {
                if (!(d.parent && d.has_child)) {
                    return 'none'
                } else {
                    return ''
                }
            })

        // 展开按钮样式
        updateNodes.selectAll('.cir-in')
            .attr('d', function(d) {
                if (d.children) {
                    return expandElbowOpen(d)
                } else {
                    return expandElbowClose(d)
                }
            })


        // enter和update部分的坐标都重新计算
        getTrueWidthAndHeight(enterNodes)
        getTrueWidthAndHeight(updateNodes)

        /* 结束节点update */

        // 3. 节点的 Exit 部分的处理办法
        var exitNodes = nodeExit.transition()
            .duration(self.duration)
            .attr('transform', function(d) {
                var o = {
                    x0: source.x,
                    y0: source.y,
                    source_parent: source.parent,
                    parent: d.parent
                }
                return transformEnter(o)
            })
            .remove()

        /* 处理连线 */

        // 获取连线的update部分
        var linkUpdate = svg.ele.select('.link_connect_group').selectAll('.link')
            .data(links, function(d) {
                return d.target.code
            })
            // 获取连线的enter部分
        var linkEnter = linkUpdate.enter()
            // 获取连线的exit部分
        var linkExit = linkUpdate.exit()

        // 1. 连线的 Enter 部分的处理办法
        var link = linkEnter
            .append('path')
            .attr('class', 'link')
            .attr('d', function(d) {
                d.z_index = 1
                var font_size = d.source.depth === 0 ? self.rootFontSize : self.childFontSize
                var o = {
                    x: source.x0,
                    y: source.y0 + (getPathWidth(d.source.name, font_size) - 20) - self.pathPadding + self.radius
                }
                return transitionElbow({
                    source: o,
                    target: o
                })
            })
            .attr('stroke-width', 0)
            .attr('stroke-opacity', 0)

        // 2. 连线的 Update 部分的处理办法
        linkUpdate.transition()
            .duration(self.duration)
            .attr('d', elbow)
            .attr('stroke-width', 1)
            .attr('stroke-opacity', 1)


        // 3. 连线的 Exit 部分的处理办法
        linkExit.transition()
            .duration(self.duration)
            .attr('d', function(d) {
                var font_size = d.source.depth === 0 ? self.rootFontSize : self.childFontSize
                var o = {
                    x: source.x,
                    y: source.y + getPathWidth(d.source.name, font_size) - 20 - self.pathPadding + self.radius
                }
                return transitionElbow({
                    source: o,
                    target: o
                })
            })
            .remove()

        /* 结束连线 */

        // 存储svg的中心点坐标
        setTimeout(addCenterToSvg, self.duration)

        if (self.hasMini) {
            // 画出缩略图
            drawPreviewer(nodes, links)
        }

        /* 将当前的节点坐标保存在变量x0、y0里，以备更新时使用 */
        nodes.forEach(function(d) {
            d.x0 = d.x
            d.y0 = d.y
        })

        /* 存储atlas_g初始位置，在父级坐标系(scale_g)里面的坐标 */
        setRootPointInSvg()
    }


    /* 存储atlas_g初始位置在外部svg里面的坐标 */
    // self.orginX, self.orginY 可能不等于localPoint,因为要加上atlas_g的位移因素
    // 不考虑atlas_g的位移时，应该是相等的
    function setRootPointInSvg() {
        var point = svg.own_svg.node().createSVGPoint()
        var transform = d3.transform(svg.scale_g.attr('transform'))
        point.x = transform.translate[0]
        point.y = transform.translate[1]

        if (!svg.localPoint) {
            // 把初始位置转化到svg_main中的坐标
            svg.localPoint = getMatrixPoint(point, svg.atlas_g.node(), svg.own_svg.node())
        }
    }

    // 初始化
    var init = function() {
        init_dom()
        addEvents()
        if (self.hasMini) {
            init_minimap()
        }
        init_toolbar()
        svg.draw(svg.data)
    }
    init()
    return svg
}

// 用法:
// svg = Tree({
//     el: '.content-main',
//     data: data,  // 树形图数据
//     editFunc: show_all_modal, // 右键编辑函数
//     hasMini: true,
//     toolbar: {
//     options: ['origin', 'zoom']
//     },
//     getFunc: ajaxPost,  //获取数据的函数
//     changeSortFunc: showSortChange,  // 修改排序序号的函数
// });


export {
    Tree
}